/**
 * 
 */
package learning.maxent.training;

import java.util.ArrayList;
import java.util.List;

import learning.data.document.InstanceDocument;
import learning.maxent.training.Maxent.DecodingResult;

public class Evaluator {
	
	public enum Level { COARSE, FINE }
	
	protected int numLabels;
	protected int[][] confusionMatrix;
	protected int documentErrors;
	protected int totalDocuments;
	protected List<Example> errors;
	protected List<InstanceDocument> correct;
	
	protected Level level;
	
	public Evaluator(Level level) {
		this.level = level;
	}
	
	public Evaluator(Level level, int numLabels) {
		this(level);
		init(numLabels);
	}

	public void init(int numLabels) {
		this.numLabels = numLabels;
		this.confusionMatrix = new int[numLabels][numLabels];
		
		if (Level.FINE.equals(level)) {
			this.errors = new ArrayList<Example>();
			this.correct = new ArrayList<InstanceDocument>();
		}
	}
	
	public void reset() {
		for (int i=0; i < numLabels; i++)
			for (int j=0; j < numLabels; j++)
				confusionMatrix[i][j] = 0;
		documentErrors = totalDocuments = 0;
		
		if (Level.FINE.equals(level)) {
			errors.clear();
			correct.clear();
		}
	}		
	
	public void update(InstanceDocument doc, DecodingResult predictedLabel, DecodingResult trueLabel) {
		
		//System.out.println(predictedParse.labels.length + " " + trueParse.labels.length);
		//System.out.println(confusionMatrix.length + " " + confusionMatrix[0].length);
		// update confusion matrix
		confusionMatrix[trueLabel.label][predictedLabel.label]++;
		
		// count token sentence/errors
		boolean correct = trueLabel.label == predictedLabel.label;

		if (!correct) {
			documentErrors++;
			if (Level.FINE.equals(level))
				errors.add(new Example(doc, predictedLabel, trueLabel));
		}
		
		if (correct) {
			if (Level.FINE.equals(level))
				this.correct.add(doc);
		}
		
		// totals
		totalDocuments++;
	}
	
	public int[][] getConfusionMatrix() {
		return confusionMatrix;
	}
	
	public int getNumLabels() { return numLabels; }
	
	public int getTotalDocuments() { return totalDocuments; }
	
	public int getDocumentErrors() { return documentErrors; }
	
	public float getDocumentErrorRate() { return (float)documentErrors / (float)totalDocuments; }
	
	public List<Example> getErrors() { return errors; }
	
	public List<InstanceDocument> getCorrect() { return correct; }
	
	public static class Example {
		public InstanceDocument doc;
		public DecodingResult predictedParse;
		public DecodingResult trueParse;
		
		public Example(InstanceDocument doc,
				DecodingResult predictedLabel,
				DecodingResult trueLabel) {
			this.doc = doc;
			this.predictedParse = predictedLabel;
			this.trueParse = trueLabel;
		}
	}
}